Skip to content

«Baum»: parameter names on a call's edges; the box in the call node's place - #57

Merged
cedricvogel-leo merged 1 commit into
mainfrom
feature/tree-calls
Nov 6, 2026
Merged

cedricvogel-leo merged 1 commit into
mainfrom
feature/tree-calls

Conversation

@cedricvogel-leo

Copy link
Copy Markdown
Collaborator

P44: two changes to calls in the mode «Baum».

1. Parameter names on the edges

  • Which calls: a function of the program's own (one with a call-enter step in that evaluation). Each edge to an argument gets a small label with the parameter it binds to: summe(2 + 2, 3 * 4) with def summe(x, y) labels the edge to 2 + 2 x and the edge to 3 * 4 y. The node keeps the function's name.
  • Keyword arguments are labelled with their parameter, and the name= node goes, since the label says it.
  • No label or no edge:
    • a parameter left to its default has no edge;
    • after a *args (a starred argument) there are no labels, and none for **kwargs;
    • built-in and library functions (len, max, sum) have no call-enter, so their edges stay unlabelled.
  • Lifetime: the labels stay through the reductions (the edge to x keeps x while 2 + 2 becomes 4), until the call is replaced or its box opens.
  • Placement: in the gap above the argument, on the side of the edge away from the parent, in the code font at 0.75 em, muted.
    • Room: the layout reserves room for each label in its node's place, so no label touches a node or another label.
    • Not avoided: another edge can still cross a label.
    • Screen readers: the text (the chain) is unchanged.

2. The box in the call node's place

  • In the tree: a call that stays a box (local variables etc.) is no longer hung below the tree. Once its frame opens, the box replaces the call node: the parent's edge leads to its top, and its siblings stay on their row. The box's header shows the binding, so there are no labels inside it.
  • The box is measured as drawn: ExpressionTreeBox reads its size in characters and rows of the tree, and the tree is a node of that size.
    • Tall nodes: the van der Ploeg port now gives a node several rows (bottom = y + h). The algorithm takes heights into account, and test:layout compares it with d3-flextree on 500 random call trees with tall boxes.
  • Positions: the tree is laid out again when the box opens and when it closes (both are growth steps, like an inline call replaced by its body). In between, nothing moves, unless the box grows: a line of it gets longer, or a tree or another box opens inside. Sizes only grow while the box is open, so stepping back and forth doesn't move it.
  • The rest stays:
    • nested boxes follow the same rule (a box line's own tree, with its calls as boxes in their places);
    • the box note («… hat lokale Variablen – …») stays at the box's top;
    • a wide tree with a box scrolls as in B.
  • One step later: in «Baum», the box now appears with the call-enter step, not one step early as a preview; the preview had no place in the tree.

Checks

  • test:tree (runtime traces):
    • summe(2 + 2, 3 * 4) gives summe(x:+(2, 2), y:*(3, 4)) → summe(x:4, …) → summe(x:4, y:12) → +(4, 12) → 16, and its text equals the chain;
    • len([1, 2]) + max(2, 5) has no labels;
    • keywords (teile(b=4, a=8) gives teile(b:4, a:8)), a default (no edge) and *[9, 3] (no labels);
    • notenschnitt([4, 5, 4.5]) + 1 gives +(notenschnitt(noten:…), 1) → +(BOX, 1) → +(4.5, 1) → 5.5, laid out again at the box's opening and closing.
  • test:layout: d3-flextree agrees on 500 random call trees with boxes of 1–6 rows and with label room, and no label overlaps a node or another label.
  • test:console (Chrome, all checks pass):
    • x and y show on exactly the three steps before the call is replaced;
    • the box sits on the row below + with 1 beside it, and nothing moves while it's open (16 steps);
    • no node, label or box overlaps once the animations have settled;
    • the embed keeps one height in both examples.
  • Also: the steady height now reads its hidden copies a frame later, after a box has been measured and its tree laid out again.
  • Unchanged and passing: lint (the known warning only), test:runtime, test:protocol, test:hints and test:svg.

Screenshots

Every step of both examples at 1000 px and 420 px (see the session report).

Manual tests

Desktop (Chrome, Safari, Firefox), an embed with features=visualize,tree:

  1. summe(2 + 2, 3 * 4): x and y beside the edges, staying through 4 and 12, gone at 4 + 12.
  2. len([1, 2]) + max(2, 5): no labels.
  3. notenschnitt([4, 5, 4.5]) + 1: the box in place of notenschnitt under +, with 1 beside it. Step through the box: the tree stays put. Then 4.5 + 1 and 5.5.
  4. A recursion (fak(3)): boxes nested in boxes, each in its node's place.

iPad (portrait and landscape), external keyboard:

  1. In example 3, at 420 px or in portrait: the tree scrolls, with the root in the middle and hints at the edges. Tab into the tree; the arrow keys and Home/End reach the box.
  2. The labels are readable.

Follow-ups (not done)

  • Scrolling to the current line: in a narrow view, the visualizer doesn't scroll a tree to follow the current line inside a box. Its scroll effect moves only the visualizer, so the learner scrolls the tree by hand.
  • A growing box moves the tree, which can happen when a tree opens inside it. Avoiding that would need the box's largest size measured in advance.
  • Edges and labels: a label can be crossed by another edge of the same parent, since only nodes and labels are kept apart.

🤖 Generated with Claude Code

… place

A call of the program's own labels each argument's edge with the
parameter it binds to (positional, by keyword; none after *args, for
**kwargs, for a default, or for built-in functions), until the call is
replaced or its box opens. The layout keeps room for the labels in each
node's place, so they touch no node and no other label.

A call that stays a box now sits in its node's place: a tree node of the
box's measured size (ExpressionTreeBox, growth-only), several rows high
(the van der Ploeg port takes a node's height into account). The tree is
laid out again when the box opens and closes, and when it grows.

Checks: test:tree (labels, keywords, builtins, the box in place),
test:layout (flextree with tall boxes and label room on 500 call trees,
no label overlapping), test:console (labels, the box under +, no
overlaps, one height, no movement while the box is open).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cedricvogel-leo
cedricvogel-leo merged commit 542adf8 into main Nov 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant